home *** CD-ROM | disk | FTP | other *** search
/ Aminet 8 / Aminet 8 (1995)(GTI - Schatztruhe)[!][Oct 1995].iso / Aminet / util / wb / opticon_1_9.lha / opticon-1.9 / opticon.c < prev    next >
C/C++ Source or Header  |  1995-07-16  |  20KB  |  656 lines

  1. /*
  2.  *  OPTICON.C
  3.  */
  4.  
  5. #include "version.h"
  6. static char versiontag[] = "$VER: $Id: opticon.c,v 1.9 1995/07/14 17:38:41 tf Exp $";
  7.  
  8. /****** OptIcon/OptIcon ******************************************************
  9. *
  10. *   NAME
  11. *       OptIcon -- Optimize icon images for size and speed (V36)
  12. *
  13. *   SYNOPSIS
  14. *       OptIcon NAME/A/M,DEPTH=PLANES/N,NOEXPAND/S,VERBOSE/S,SMART/S
  15. *
  16. *   FUNCTION
  17. *       OptIcon reads in given ".info" files and scans the icon image
  18. *       in order to optimize the PlanePick and PlaneOnOff fields in the
  19. *       icon Image structure.  This is a space-saving mechanism for image
  20. *       data.
  21. *       Rather than defining the image data for every plane of the RastPort,
  22. *       you need define data only for the planes that are not entirely zero
  23. *       or one.  As you define your Imagery, you will often find that most
  24. *       of the planes ARE just as color selectors.  For instance, if you're
  25. *       designing a two-color icon to use colors one and three, and the icon
  26. *       will reside in a five-plane display, bit plane zero of your
  27. *       imagery would be all ones, bit plane one would have data that
  28. *       describes the imagery, and bit planes two through four would be
  29. *       all zeroes.  Using these flags avoids wasting all that memory in
  30. *       this way:  first, you specify which planes you want your data to
  31. *       appear in using the PlanePick variable.  For each bit set in the
  32. *       variable, the next "plane" of your image data is blitted to the
  33. *       display.  For each bit clear in this variable, the corresponding bit
  34. *       in PlaneOnOff is examined.  If that bit is clear, a "plane" of zeroes
  35. *       will be used.  If the bit is set, ones will go out instead.
  36. *       Note that if you want an Image that is only a filled rectangle, you
  37. *       can get this by setting PlanePick to zero (pick no planes of data)
  38. *       and set PlaneOnOff to describe the pen color of the rectangle.
  39. *
  40. *   INPUTS
  41. *       NAME       - name of the icon image file.  A trailing ".info"
  42. *                    is optional but not required.
  43. *       DEPTH      - maximum number of bitplanes to be saved.
  44. *       VERBOSE    - display input and output information for each icon.
  45. *
  46. *   EXAMPLE
  47. *       ;Remove all but the first 3 planes of the icon image for the
  48. *       ;disk in drive DF0: but don't add any planes
  49. *       opticon df0:disk planes=3 noexpand
  50. *
  51. *   NOTES
  52. *       Since the IconEdit from Commodore will always save 8 bitplane icons
  53. *       the above example might be of great use to you.  (Note that 3 plane
  54. *       images are not only smaller but also faster!)
  55. *       Coming with OptIcon is the script PatchIcons which will recursively
  56. *       descend all subdirectories of a given path deleting all but the first
  57. *       3 planes of all icon images in that path.
  58. *
  59. *       OptIcon now also allows you to expand your 8 or more color icons
  60. *       for the use on a 16 or more color Workbench.  This is important due
  61. *       to the new color system under OS3.x which always shifts the second
  62. *       four colors to the end of the system palette.  Therefore you might
  63. *       want to adapt an icon's color depth to the actual screenmode it is
  64. *       used on.
  65. *
  66. *   EXAMPLE
  67. *       ;Remap the last 4 of at least 8 colors of the RAM DISK icon
  68. *       ;to the last 4 colors in a 16 or more colors Workbench palette
  69. *       opticon ram:disk planes=4
  70. *
  71. *   NOTE ALSO
  72. *       With the new option SMART/S OptIcon will examine WBDRAWER icons
  73. *       more closely and if there is not really a drawer (or a file 8-)
  74. *       behind the icon then the icon type is changed into WBTOOL.  This
  75. *       is a great help if you want to use some drag'n drop application to
  76. *       update icon images which would have problems otherwise.
  77. *
  78. *   BUGS
  79. *       Commodore's PutDiskObject() currently [icon.library 40.1 (15.2.93)]
  80. *       re-expands icon images using the PlanePick/PlaneOnOff mechanism and
  81. *       in fact PutDiskObject() has quite a lot of problems doing so!
  82. *       For this reason OptIcon will perform the PlanePick/PlaneOnOff
  83. *       optimization only if the keyword CRITICAL is given in the command
  84. *       line.
  85. *
  86. *   DISCLAIMER
  87. *       This file is part of the Icon2C and OptIcon distribution.
  88. *
  89. *       Icon2C and OptIcon are free software; you can redistribute them
  90. *       and/or modify them under the terms of the GNU General Public License
  91. *       as published by the Free Software Foundation; either version 1 of
  92. *       the License, or (at your option) any later version.
  93. *
  94. *       Icon2C and Opticon are distributed in the hope that they will be
  95. *       useful, but WITHOUT ANY WARRANTY; without even the implied warranty
  96. *       of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  97. *       GNU General Public License for more details.
  98. *
  99. *       You should have received a copy of the GNU General Public License
  100. *       along with these programs; see the file COPYING.  If not, write to
  101. *       the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  102. *
  103. *   COPYRIGHT
  104. *       Icon2C and OptIcon are Copyright (C)1994 by Tobias Ferber.
  105. *       You can reach me via E-mail: ukjg@rz.uni-karlsruhe.de
  106. *
  107. *   SEE ALSO
  108. *       PatchIcons, Icon2C
  109. *
  110. ******************************************************************************
  111. *
  112. *       Compile w/ -DDEBUG to output more information at runtime
  113. */
  114.  
  115. #include <ctype.h>
  116. #include <stdlib.h>
  117. #include <string.h>
  118. #include <stdio.h>
  119.  
  120. #include <exec/types.h>
  121. #include <exec/memory.h>
  122.  
  123. #include <dos/dos.h>
  124. #include <dos/rdargs.h>
  125.  
  126. #include <intuition/intuition.h>
  127. #include <intuition/intuitionbase.h>
  128.  
  129. #include <workbench/workbench.h>
  130. #include <workbench/startup.h>
  131. #include <workbench/icon.h>
  132.  
  133. #include "memfn.h"
  134.  
  135. #ifdef __GNUC__
  136. /* suggest parentheses around assignment used as truth value */
  137. #define if(assignment) if( (assignment) )
  138. #endif /* __GNUC__ */
  139.  
  140. extern struct Library *OpenLibrary(STRPTR, ULONG);
  141. extern void CloseLibrary(struct Library *);
  142. extern void CopyMem(APTR, APTR, ULONG);
  143. extern void *AllocMem(ULONG, ULONG);
  144. extern void FreeMem(void *, ULONG);
  145. extern ULONG TypeOfMem(void *);
  146. extern struct RDArgs *ReadArgs(STRPTR, LONG *, struct RDArgs *);
  147. extern LONG IoErr(void);
  148. extern BOOL PrintFault(LONG, STRPTR);
  149. extern void FreeArgs(struct RDArgs *);
  150. extern struct DiskObject *GetDiskObject(char *);
  151. extern BOOL PutDiskObject(char *, struct DiskObject *);
  152. extern void FreeDiskObject(struct DiskObject *);
  153.  
  154. struct IconBase *IconBase;
  155.  
  156. void display_version_information(void)
  157. {
  158.   static char license[]=
  159.     "OptIcon is free software; you can redistribute it and/or modify\n"
  160.     "it under the terms of the GNU General Public License as published\n"
  161.     "by the Free Software Foundation; either version 1 of the License,\n"
  162.     "or (at your option) any later version.\n"
  163.     "\n"
  164.     "OptIcon is distributed in the hope that it will be useful,\n"
  165.     "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
  166.     "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
  167.     "GNU General Public License for more details.\n"
  168.     "\n"
  169.     "You should have received a copy of the GNU General Public License\n"
  170.     "along with OptIcon; see the file COPYING.  If not, write to the\n"
  171.     "Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
  172.     ;
  173.  
  174.   puts("\nOptIcon Version " VERSION " (compiled " __DATE__ ", " __TIME__ ")\n"
  175.        "(c)Copyright 1994 by Tobias Ferber, ukjg@rz.uni-karlsruhe.de\n");
  176.  
  177.   puts(license);
  178. }
  179.  
  180.  
  181. struct Image *free_image(struct Image *i)
  182. {
  183.   if(i)
  184.   {
  185.     long size= i->Depth * i->Height * ((i->Width + 15) / 16) * sizeof(UWORD);
  186.  
  187.     if(i->ImageData && size > 0)
  188.       FreeMem( i->ImageData, size );
  189.  
  190.     FreeMem( i, sizeof(struct Image) );
  191.   }
  192.  
  193.   return (struct Image *)0L;
  194. }
  195.  
  196. /* command line options */
  197. #define OPT_NOEXPAND  (1<<0)
  198. #define OPT_CRITICAL  (1<<1)
  199. #define OPT_VERBOSE   (1<<2)
  200. #define OPT_REMAPV37  (1<<3)
  201.  
  202. struct Image *optimize_image(struct Image *i, WORD planes, int optimode)
  203. {
  204.   UWORD p16= i->Height * ((i->Width + 15) / 16); /* #of words per plane */
  205.   UWORD *idata= i->ImageData;
  206.   WORD d, dmax, D, P;
  207.   UBYTE pp= 0;    /* plane pick */
  208.   UBYTE p10= 0;   /* plane on/off */
  209.  
  210.   struct Image *o= i;  /* optimized image */
  211.  
  212.   /* prevent silly args from being harmful */
  213.  
  214.   if(!i)
  215.     return i;
  216.  
  217.   if(planes > 8)
  218.     planes= 8;
  219.  
  220.   if(optimode & OPT_VERBOSE)
  221.   {
  222.     printf("(depth=%d, pick=%d, onoff=%d)", i->Depth,
  223.                                             i->PlanePick,
  224.                                             i->PlaneOnOff);
  225.     fflush(stdout);
  226.   }
  227.  
  228.   /*
  229.       PRESCAN:  Examine dmax planes of i and compute
  230.  
  231.         D   = the real depth (without trailing 0 planes)
  232.         pp  = the new PlanePick value
  233.         p10 = the new PlaneOnOff value
  234.   */
  235.  
  236.   dmax= (0 < planes && planes < i->Depth) ? planes : i->Depth;
  237.  
  238.   for(d= D= 0; d<dmax; d++)
  239.   {
  240.     /* check if we have some image data for plane d */
  241.     if(i->PlanePick & (1<<d))
  242.     {
  243.       UWORD n, *p, v;
  244.  
  245.       /* scan the image data of plane d */
  246.       for(n=0, p=idata, v=*p; n < p16; n++, p++)
  247.         if(*p != v)
  248.           break;
  249.  
  250.       if(n==p16 && v==0xFFFF) /* plane d is entirely 1 */
  251.         p10 |= (1<<d);  /* pp bit is already 0 */
  252.  
  253.       if( n!=p16 || (n==p16 && v!=0x0000 && v!=0xFFFF) )
  254.         pp |= (1<<d);
  255.  
  256.       if( n!=p16 || (n==p16 && v!=0x0000) )
  257.         D= d;
  258.  
  259.       idata= &idata[p16];
  260.     }
  261.     else if(i->PlaneOnOff & (1<<d))
  262.     {
  263.       p10 |= (1<<d);
  264.       D=d;
  265.     }
  266.   }
  267.  
  268.   ++D;
  269.  
  270.   if( (optimode & OPT_VERBOSE) && (D != dmax || pp != i->PlanePick || p10 != i->PlaneOnOff) )
  271.   {
  272.     printf(" -> (%d,%d,%d)", D,pp,p10);
  273.     fflush(stdout);
  274.   }
  275.  
  276.   /* compute the #of planes in the output image */
  277.   P= ( planes>D && !(optimode & OPT_NOEXPAND) ) ? planes : D;
  278.  
  279.   if(P != i->Depth || pp != i->PlanePick || p10 != i->PlaneOnOff)
  280.   {
  281.     UWORD p8= p16 * sizeof(UWORD);
  282.     UWORD *odata;
  283.     ULONG osize= P * p8;
  284.  
  285.     if( o= (struct Image *)AllocMem(sizeof(struct Image),MEMF_CLEAR) )
  286.     {
  287.       if( odata= (UWORD *)AllocMem(osize,TypeOfMem(i->ImageData)|MEMF_CLEAR) )
  288.       {
  289.         CopyMem( (APTR)i, (APTR)o, sizeof(struct Image) );
  290.         o->ImageData= odata;
  291.  
  292.         idata= i->ImageData;
  293.  
  294.         for(d=0; d<D; d++)
  295.         {
  296.           if( pp & (1<<d) )
  297.           {
  298.             if(i->PlanePick & (1<<d))
  299.             {
  300.               CopyMem( (APTR)idata, (APTR)odata, p8 );
  301.               idata= &idata[p16];
  302.               odata= &odata[p16];
  303.             }
  304.             else /* !PlanePick bit (should not happen) */
  305.             {
  306.               memset( (char *)odata, (i->PlaneOnOff & (1<<d)) ? 0xFF : 0x00, p8 );
  307.               odata= &odata[p16];
  308.             }
  309.           }
  310.           else /* !pp bit */
  311.           {
  312.             if(i->PlanePick & (1<<d))
  313.               idata= &idata[p16];
  314.  
  315.             if( !(optimode & OPT_CRITICAL) )
  316.             {
  317.               memset( (char *)odata, (p10 & (1<<d)) ? 0xFF : 0x00, p8 );
  318.               odata= &odata[p16];
  319.               pp |= (1<<d);
  320.               p10 &= ~(1<<d);
  321.             }
  322.           }
  323.         }
  324.  
  325.         if(D>=3 && D<P) /* no need to check OPT_NOEXPAND sice P is < D if set */
  326.         {
  327.           UWORD *p;
  328.  
  329.           if( p= (UWORD *)malloc(p8) )
  330.           {
  331.  
  332.             if( (optimode & OPT_REMAPV37) && p10<=7 )
  333.             {
  334.               /*
  335.                   REMAP:  Make colors 4-7 become the last 4 in the palette
  336.  
  337.                   Algo: (1) OR together all planes > 2,
  338.                         (2) invert the result,
  339.                         (3) AND it with plane 2 and
  340.                         (4) OR the result with all planes > 2
  341.  
  342.                   Note: There is no need to expand the image data if p10 &~ %111 != 0
  343.               */
  344.  
  345.               /* move to plane 2 */
  346.  
  347.               idata= i->ImageData;
  348.  
  349.               for(d=0; d<2; d++)
  350.                 if(i->PlanePick & (1<<d))
  351.                   idata= &idata[p16];
  352.  
  353.               if(i->PlanePick & (1<<2))
  354.               {
  355.                 memcpy((char *)p, (char *)idata, p8);
  356.                 idata= &idata[p16];
  357.               }
  358.               else memset( (char *)p, (p10 & (1L<<2)) ? 0xFF : 0x00, p8 );
  359.  
  360.               /* or planes 3..D, invert them, AND the result with plane 2 */
  361.  
  362.               for(d=3; d<D; d++)
  363.               {
  364.                 if(i->PlanePick & (1<<d))
  365.                 {
  366.                   memandnot( (char *)p, (char *)idata, p8 );
  367.                   idata= &idata[p16];
  368.                 }
  369.                 /* else bit d of i->PlaneOnOff is 0 --> no-op */
  370.               }
  371.  
  372.               /* move to plane 3 */
  373.  
  374.               odata= o->ImageData;
  375.  
  376.               for(d=0; d<3; d++)
  377.                 if(pp & (1<<d))
  378.                   odata= &odata[p16];
  379.  
  380.               for(d=3; d<P; d++)
  381.               {
  382.                 if( d>=D || pp & (1<<d) )
  383.                 {
  384.                   memor( (char *)odata, (char *)p, p8 );
  385.                   odata= &odata[p16];
  386.                   pp |= (1<<d);
  387.                 }
  388.               }
  389.             }
  390.  
  391.             else /* !REMAPV37 */
  392.             {
  393.               /*
  394.                   EXPAND:  Remap the last 4 colors of i to the last 4 colors of o
  395.  
  396.                   Algo: (1) OR together all planes but the last
  397.                         (2) AND the result with the last plane
  398.                         (3) set the result in all new planes
  399.  
  400.                   Note: if any plane of i but the last is entirely 1 then we can
  401.                         simply copy the last plane of i to all new planes in o
  402.               */
  403.  
  404.               idata= i->ImageData;
  405.  
  406.               if( p10 &~ (1<<(D-1)) == 0)
  407.               {
  408.                 memset( (char *)p, 0x00, p8 );
  409.  
  410.                 for(d=0; d<D-1; d++)
  411.                 {
  412.                   if(i->PlanePick & (1<<d))
  413.                   {
  414.                     memor( (char *)p, (char *)idata, p8 );
  415.                     idata= &idata[p16];
  416.                   }
  417.                 }
  418.                 /* else plane d is entirely 0 */
  419.  
  420.                 if( i->PlanePick & (1<<(D-1)) )
  421.                   memand( (char *)p, (char *)idata, p8 );
  422.                 /* else the last plane is entirely 1 */
  423.               }
  424.               else /* move to the last plane */
  425.               {
  426.                 for(d=0; d<D-1; d++)
  427.                   if(i->PlanePick & (1<<d))
  428.                     idata= &idata[p16];
  429.  
  430.                 if( i->PlanePick & (1<<(D-1)) )
  431.                   memcpy( (char *)p, (char *)idata, p8 );
  432.                 else
  433.                   memset( (char *)p, 0xFF, p8 );
  434.               }
  435.  
  436.               /* move to plane D */
  437.  
  438.               odata= o->ImageData;
  439.  
  440.               for(d=0; d<D; d++)
  441.                 if(pp & (1<<d))
  442.                   odata= &odata[p16];
  443.  
  444.               for(d=D; d<P; d++)
  445.               {
  446.                 memcpy( (char *)odata, (char *)p, p8 );
  447.                 odata= &odata[p16];
  448.                 pp |= (1<<d);
  449.               }
  450.  
  451.             }
  452.  
  453.             free(p);
  454.           }
  455.           else /* !p --> panic! */
  456.           {
  457.             FreeMem(o->ImageData,osize);
  458.             FreeMem(o,sizeof(struct Image));
  459.             o= (struct Image *)0L;
  460.           }
  461.         }
  462.  
  463.         o->Depth= P;
  464.         o->PlanePick= pp;
  465.         o->PlaneOnOff= p10;
  466.  
  467.       }
  468.       else /* !odata */
  469.       {
  470.         FreeMem(o,sizeof(struct Image));
  471.         o= (struct Image *)0L;
  472.       }
  473.     }
  474.   }
  475.  
  476.   if(optimode & OPT_VERBOSE)
  477.   {
  478.     if(o && o!=i)
  479.       printf(" -> (%d,%d,%d)", o->Depth, o->PlanePick, o->PlaneOnOff);
  480.     putchar('\n');
  481.   }
  482.  
  483.   return o;
  484. }
  485.  
  486.  
  487. int main(int argc, char **argv)
  488. {
  489.   struct RDArgs *a;
  490.   LONG args[7] = { 0,0,0,0,0,0,0 };
  491.  
  492.   WORD numplanes= 0;
  493.   char *whoami= *argv;
  494.   int rc= RETURN_OK;
  495.  
  496.   if( a= ReadArgs("NAME/A/M,DEPTH=PLANES/N,NOEXPAND/S,CRITICAL/S,REMAPV37/S,VERBOSE/S,SMART/S", args, NULL) )
  497.   {
  498.     char **flist= (char **)args[0];
  499.  
  500.     if(args[1])
  501.     {
  502.       if( (numplanes= (WORD)*(LONG *)(args[1])) < 1 )
  503.       {
  504.         fprintf(stderr,"%s: Illegal maximum depth %d\n",whoami,numplanes);
  505.         rc= RETURN_FAIL;
  506.       }
  507.     }
  508.  
  509.     if(flist && rc == RETURN_OK)
  510.     {
  511.       if( IconBase= (struct IconBase *)OpenLibrary(ICONNAME,36) )
  512.       {
  513.         while(*flist && rc == RETURN_OK)
  514.         {
  515.           char *iname= (char *)malloc( strlen(*flist) + 1 );
  516.  
  517.           if(iname)
  518.           {
  519.             struct DiskObject *icon;
  520.             strcpy(iname, *flist);
  521.  
  522.             if( (icon= GetDiskObject(iname)) == NULL )
  523.             {
  524.               int x= strlen(iname) - 5;
  525.               if(x>0 && !stricmp(&(iname[x]),".info"))
  526.               {
  527.                 iname[x]= '\0';
  528.                 icon= GetDiskObject(iname);
  529.               }
  530.             }
  531.  
  532.             if(icon)
  533.             {
  534.               struct Gadget *g= &icon->do_Gadget;
  535.  
  536.               struct Image *ogr, *osr;
  537.               int modified= 0;
  538.               int flags= 0;
  539.  
  540.               ogr= osr= (struct Image *)0L;
  541.  
  542.               if(args[2]) flags |= OPT_NOEXPAND;
  543.               if(args[3]) flags |= OPT_CRITICAL;
  544.               if(args[4]) flags |= OPT_REMAPV37;
  545.               if(args[5]) flags |= OPT_VERBOSE;
  546.  
  547.               if(g->GadgetRender && (g->Flags & GFLG_GADGIMAGE))
  548.               {
  549.                 struct Image *i= (struct Image *)g->GadgetRender;
  550.  
  551.                 if(flags & OPT_VERBOSE)
  552.                   printf("Normal   ");
  553.  
  554.                 if( ogr= optimize_image(i,numplanes,flags) )
  555.                 {
  556.                   if(ogr != i)
  557.                   {
  558.                     g->GadgetRender= (APTR)ogr;
  559.                     ++modified;
  560.                   }
  561.                   else ogr= (struct Image *)0L; /* don't free ogr */
  562.  
  563.                   if(g->SelectRender && (g->Flags & GFLG_GADGHIMAGE))
  564.                   {
  565.                     i= (struct Image *)g->SelectRender;
  566.  
  567.                     if(flags & OPT_VERBOSE)
  568.                       printf("Selected ");
  569.  
  570.                     if( osr= optimize_image(i,numplanes, flags) )
  571.                     {
  572.                       if(osr != i)
  573.                       {
  574.                         g->SelectRender= (APTR)osr;
  575.                         ++modified;
  576.                       }
  577.                       else osr= (struct Image *)0L; /* don't free osr */
  578.                     }
  579.                     else
  580.                     {
  581.                       fprintf(stderr,"%s: %s.info: not enough free memory to optimize the selected image\n",whoami,iname);
  582.                       rc= RETURN_ERROR;
  583.                     }
  584.                   }
  585.                 }
  586.                 else
  587.                 {
  588.                   fprintf(stderr,"%s: %s.info: not enough free memory to optimize the normal image\n",whoami,iname);
  589.                   rc= RETURN_ERROR;
  590.                 }
  591.               }
  592.  
  593.               /* SMART/S */
  594.  
  595.               if( rc == RETURN_OK && args[6] && icon->do_Type == WBDRAWER )
  596.               {
  597.                 BPTR lock= Lock(iname,ACCESS_READ);
  598.  
  599.                 if( BADDR(lock) )
  600.                   UnLock(lock);
  601.  
  602.                 else
  603.                 {
  604.                   icon->do_Type = WBTOOL;
  605.                   ++modified;
  606.                 }
  607.               }
  608.  
  609.               if( modified && rc == RETURN_OK )
  610.               {
  611.                 if( !PutDiskObject(iname,icon) )
  612.                   PrintFault(rc= IoErr(), iname);
  613.               }
  614.  
  615.               if(ogr) ogr= free_image(ogr);
  616.               if(osr) osr= free_image(osr);
  617.  
  618.               FreeDiskObject(icon);
  619.             }
  620.             else /* !icon */
  621.             {
  622.               fprintf(stderr,"%s: GetDiskObject() failed for %s[.info]\n",whoami,iname);
  623.               rc= IoErr();
  624.             }
  625.  
  626.             free(iname);
  627.           }
  628.           else /* !iname */
  629.           {
  630.             fprintf(stderr,"%s: out of memory... aaaiiiiiieeeeeeeee!\n",whoami);
  631.             rc= RETURN_ERROR;
  632.           }
  633.  
  634.           ++flist;
  635.         }
  636.         CloseLibrary((struct Library *)IconBase);
  637.       }
  638.       else
  639.       {
  640.         fprintf(stderr,"%s: You need %s V36+",whoami,ICONNAME);
  641.         rc= RETURN_ERROR;
  642.       }
  643.     }
  644.     FreeArgs(a);
  645.   }
  646.   else /* !ReadArgs */
  647.   {
  648.     if(argc == 1)
  649.       display_version_information();
  650.     else
  651.       PrintFault(IoErr(), NULL);
  652.   }
  653.  
  654.   exit(rc);
  655. }
  656.